package com.yds.modewithprinceple.singleton;

/**
 * @author YDS
 * @date 2021/5/7
 * @discribe Double Check Lock 双重锁
 *
 * 1、构造函数用private修饰，外部无法访问
 * 2、使用的时候即调用getInstance的时候才初始化
 * 3、static关键字修饰，静态变量，存储在内存中，只有一份数据
 * 4、synchronized线程安全，多线程情况下单例的唯一性
 * 5、两次判断空，避免多次同步(synchronized)
 * 缺点:
 * 由于jvm特性，允许乱序执行，上面三句代码顺序不定，那么就可能出现DCL失效的问题。
 * 步骤一、倘若A线程执行getmInstance(),还没执行构造方法SingletionDLC()
 * 步骤二、此时B线程调用getmInstance()。因为A已经执行getmInstance()，所以mInstance不为空就直接获取。
 * 步骤三、由于B直接获取，而真实情况是A线程构造方法还未执行，所以mInstance就为空了。
 * 虽然此情况发生概率较小，但也是一种情况。为了解决这种情况，java1.6开始加入volatile关键字
 */
public class SingletonDCL {
    private SingletonDCL() {
    }

    /**
     * volatile 的读性能消耗与普通变量几乎相同，但是写操作稍慢，
     * 因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行,
     * 因此在读取volatile类型的变量时总会返回最新写入的值。
     */
    private volatile static SingletonDCL instance;

    public static SingletonDCL getInstance() {
        if (null == instance) {
            synchronized (SingletonDCL.class) {
                if (null == instance) {
                    instance = new SingletonDCL();
                }
            }
        }

        return instance;
    }

}
